import { random } from 'lodash'

/**
 * 时间格式化
 * yyyy-MM-dd hh:mm:ss.S
 * @param tmp
 * @param fmt
 */
export const formatTime = function(tmp: number | string, fmt = 'yyyy-MM-dd hh:mm:ss') {
  const date = new Date(tmp)
  const o = {
    'M+': date.getMonth() + 1, // 月份
    'd+': date.getDate(), // 日
    'h+': date.getHours(), // 小时
    'm+': date.getMinutes(), // 分
    's+': date.getSeconds(), // 秒
    'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
    S: date.getMilliseconds() // 毫秒
  }
  if (/(y+)/.test(fmt)) {
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
  }
  for (const k in o) {
    if (new RegExp('(' + k + ')').test(fmt)) {
      fmt = fmt.replace(
        RegExp.$1,
        RegExp.$1.length === 1
          ? // @ts-ignore
            o[k]
          : // @ts-ignore
            ('00' + o[k]).substr(('' + o[k]).length)
      )
    }
  }
  return fmt
}

/**
 * 秒转换 x天x小时x分钟x秒
 * @param t
 * @param format
 */
export const secondsFormat = (t: number, format = 'd h m') => {
  const s = Math.abs(t)

  if (s < 60) return s + '秒'

  const hasDay = format.indexOf('d') !== -1
  const hasHour = format.indexOf('h') !== -1
  const hasMin = format.indexOf('m') !== -1
  const hasSecond = format.indexOf('s') !== -1

  // 多少天，向下取整
  let day = Math.floor(s / (24 * 3600))
  // 减去天的小时数
  let hour = Math.floor((s - day * 24 * 3600) / 3600)
  // 除去小时和天的分钟
  let minute = Math.floor((s - day * 24 * 3600 - hour * 3600) / 60)
  // 除去天，小时和分钟的秒
  let second = s - day * 24 * 3600 - hour * 3600 - minute * 60

  !hasDay && (hour += day * 24)
  !hasHour && (minute += hour * 60)
  !hasMin && (second += minute * 60)

  const dayStr = day ? day + '天' : null
  const hourStr = hour ? hour + '小时' : null
  const minuteStr = minute ? minute + '分钟' : null
  const secondStr = second ? second + '秒' : null

  const arr = []

  // 天
  hasDay && arr.push(dayStr)
  // 小时
  hasHour && arr.push(hourStr)
  // 分
  hasMin && arr.push(minuteStr)
  // 秒
  hasSecond && arr.push(secondStr)

  return arr.join('')
}

/**
 * 浏览器类型，一般用来在下载页是否显示遮罩
 */
export function getBrowserType() {
  const ua = navigator.userAgent.toLowerCase()

  // HuaweiBrowser
  const Reg = {
    wx: ua.match(/MicroMessenger/i), // 微信
    qq: ua.match(/QQ/i) && !ua.match(/ QQ/i), // QQ浏览器
    qqApp: ua.match(/ QQ/i), // QQ APP[qq app中ua头就比qq浏览器多了一个空格]
    aliPay: ua.match(/Alipay/i), // 支付宝
    lark: ua.match(/Lark/i) // 飞书
  }

  let browser = 'otherBrowser'

  for (const key in Reg) {
    // @ts-ignore
    if (Reg[key]) {
      browser = key
      break
    }
  }

  return browser
}

/**
 * 延迟执行
 * @param t
 */
export function sleep(t = 1000) {
  return new Promise<void>(resolve => {
    setTimeout(() => {
      resolve()
    }, t)
  })
}

/**
 * 品牌判断
 */
export function judgeBrand() {
  const sUserAgent = navigator.userAgent.toLowerCase()

  const isIphone = sUserAgent.match(/iphone/i)
  const isHuawei = sUserAgent.match(/huawei/i)
  const isHonor = sUserAgent.match(/honor/i)
  const isOppo = sUserAgent.match(/oppo/i)
  const isOppoR15 = sUserAgent.match(/pacm00/i)
  const isVivo = sUserAgent.match(/vivo/i)
  const isXiaomi = sUserAgent.match(/mi\s/i)
  const isXiaomi2s = sUserAgent.match(/mix\s/i)
  const isRedmi = sUserAgent.match(/redmi/i)
  const isSamsung = sUserAgent.match(/sm-/i)

  if (isIphone) {
    return 'iphone'
  } else if (isHuawei || isHonor) {
    return 'huawei'
  } else if (isOppo || isOppoR15) {
    return 'oppo'
  } else if (isVivo) {
    return 'vivo'
  } else if (isXiaomi || isRedmi || isXiaomi2s) {
    return 'xiaomi'
  } else if (isSamsung) {
    return 'samsung'
  } else {
    return 'default'
  }
}

/**
 * 跳转安卓应用商店,通用链接小米会打开失败
 *
 * 通用 market://details?id=xxx
 * 华为市场 appmarket://details?id=xxx
 * 小米商店 mimarket://details?id=xxx
 * 应用宝  tmast://appdetails?pname=xxx
 * @param appName `com.babycare.parent`
 */
export function toAndroidAppStore(appName: string) {
  if (judgeBrand() === 'xiaomi') {
    window.location.href = 'mimarket://details?id=' + appName
  } else {
    window.location.href = 'market://details?id=' + appName
  }
}

/**
 * 跳转App store
 * @param id `id1551921897`
 */
export function toIOSAppStore(id: string) {
  window.location.href = 'itms-appss://apps.apple.com/cn/app/' + id
}

/**
 * 数组转树,递归求解
 * @param list
 * @param parId 终止条件，比如，pid为0的时候说明已经没有父级了
 * @param idAttrName
 * @param pidAttrName
 * @example
 *  let attr = [
 *    {id:2, name:'部门B', parentId:0},
 *    {id:3, name:'部门C', parentId:1},
 *    {id:1, name:'部门A', parentId:2},
 *    {id:4, name:'部门D', parentId:1},
 *    {id:5, name:'部门E', parentId:2},
 *    {id:6, name:'部门F', parentId:3},
 *    {id:7, name:'部门G', parentId:2},
 *    {id:8, name:'部门H', parentId:4}
 *  ]
 *  // 转树形
 *  toTree(arr,0)
 */
export function toTree(list: string | any[], parId: any, idAttrName = 'id', pidAttrName = 'pid') {
  let len = list.length

  function loop(parId: any) {
    let res = []
    for (let i = 0; i < len; i++) {
      let item = list[i]
      if (item[pidAttrName] === parId) {
        item.children = loop(item[idAttrName])
        res.push(item)
      }
    }
    return res
  }

  return loop(parId)
}

/**
 * 节流
 * @param fn
 * @param delay
 */
export function throttle(
  fn: { apply: (arg0: any, arg1: any[]) => void },
  delay: number | undefined
) {
  let timer
  let flag = true

  return function(...args: any[]) {
    if (!flag) {
      return
    }
    flag = false
    timer = setTimeout(() => {
      fn.apply(null, args)
      flag = true
    }, delay)
  }
}

/**
 * 防抖
 * @param fn
 * @param wait
 */
export function debounce(fn: (...args: any[]) => void, wait: number) {
  let timer: any = null

  return () => {
    clearTimeout(timer)
    timer = setTimeout(fn, wait)
  }
}

/*
// 可考虑批量注册函数
var Type = {};

// for 还能这么写。。。，但是可以反手一个 forEach
for (var i = 0, type; (type = ["String", "Array"][i++]); ) {
  (function (type) {
    Type["is" + type] = function (obj) {
      return Object.prototype.toString.call(obj) === `[object ${type}]`;
    };
  })(type);
}*/
/**
 * 判断类型
 * @param type js中的数据类型
 * @export isType("String")("ha")
 */
export function isType(type: String) {
  return (obj: any) => Object.prototype.toString.call(obj) === `[object ${type}]`
}

/**
 * 权重函数
 * @param weightList 权重数组，类似 flex 中是数
 * @example randomWeight[2, 4, 6] => 根据权重可能返回数组中的任意一个下标(0|1|2)；
 * 但是返回返回2的概率是： 6/12
 * 1的概率是：4/12
 * 0的概率是：2/12
 */
export function randomWeight(weightList: number[]): number {
  const arr = []
  const max = weightList.reduce((pre, currentValue) => pre + currentValue, 0)
  const random = Math.floor(Math.random() * max)

  for (let i = 0; i < weightList.length; i++) {
    for (let j = 0; j < weightList[i]; j++) {
      arr.push(i)
    }
  }

  return arr[random]
}

/**
 * 生成随机手机号
 */
export function randomPhoneNumber(): string {
  // 移动开头的号码
  const CMCC = [
    134,
    135,
    136,
    137,
    138,
    139,
    147,
    150,
    151,
    152,
    157,
    158,
    159,
    187,
    188,
    182,
    183,
    184,
    178,
    198
  ]
  // 联通开头
  const Unicom = [130, 131, 132, 145, 155, 156, 175, 176, 185, 186, 166, 146]
  // 电信开头
  const Telecom = [133, 153, 149, 173, 177, 180, 181, 189]
  // 全部的集合
  // @ts-ignore
  const preNumList: number[] = [].concat(CMCC, Unicom, Telecom)

  let restNum = ''
  for (let i = 0; i < 8; i++) {
    restNum += Math.ceil(Math.random() * 9)
  }

  return preNumList[Math.ceil(Math.random() * preNumList.length - 1)] + restNum
}

/**
 * 找到最小值的索引
 * @param arr
 */
export const findMinIndex = (arr: number[]) => {
  return arr.findIndex(it => it === Math.min(...arr))
}

/**
 * 找到 arr 中距离 value 最近的索引
 * @param arr
 * @param value
 * @example
 *  -> findDiffMin([1, 0, 2, 5, 6, 9], 3)
 *  -> 2
 */
export const findDiffMin = (arr: number[], value: number) => {
  const diffArr = arr.map(it => Math.abs(it - value))
  return findMinIndex(diffArr)
}

/**
 * 串联执行多个promise函数
 * @param list
 * @param initValue
 * @example
 * 每个任务都要接受上一个任务都返回值
 *
 * const task1 = (v) => {
 *   return new Promise((resolve) => {
 *     setTimeout(() => {
 *       console.log("t1", v);
 *       resolve(v + 1);
 *     }, 1000);
 *   });
 * };
 * const task2 = (v) =>
 *   new Promise((resolve) => {
 *     setTimeout(() => {
 *       console.log("t2", v);
 *       resolve(v + 1);
 *     }, 1000);
 *   });
 * const task3 = (v) =>
 *   new Promise((resolve) => {
 *     setTimeout(() => {
 *       console.log("t3", v);
 *       resolve(v + 1);
 *     }, 1000);
 *   });
 * const task4 = (v) =>
 *   new Promise((resolve) => {
 *     setTimeout(() => {
 *       console.log("t4", v);
 *       resolve(v + 1);
 *     }, 1000);
 *   })
 *
 * const taskList = [task1, task2, task3, task4];
 *
 * runAwayPromise(taskList).then((res) => {
 *   // 4
 *   console.log(res);
 * });
 *
 * // 输出
 * t1 0
 * t2 1
 * t3 2
 * t4 3
 * 4
 */
export function runAwayPromise(list: Array<(prevValue: any) => Promise<any>>, initValue = 0) {
  let currentIndex = 0

  const recursion = (fnPromise: (prevValue: any) => any, prevValue: any) => {
    return fnPromise(prevValue).then((value: any) => {
      currentIndex++
      if (currentIndex <= list.length - 1) {
        return recursion(list[currentIndex], value)
      }
      return value
    })
  }

  return recursion(list[currentIndex], initValue)
}

/**
 * bs64Data 转 blob
 * @param bs64Data base64格式字符串；前面不带格式的；不是这种 
 * @param mime https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
 * @example
 *   const blob = dataURLtoBlob("UEsDBBQACAgIAJCKh1UAAAAAAAA...", 'application/vnd.ms-excel')
 *   document.getElementById("download").href = URL.createObjectURL(blob)
 */
export function dataURLtoBlob(bs64Data: string, mime: string) {
  let base64Str = atob(bs64Data),
    n = base64Str.length,
    u8arr = new Uint8Array(n)
  while (n--) {
    u8arr[n] = base64Str.charCodeAt(n)
  }
  return new Blob([u8arr], { type: mime })
}

/**
 * 和上面是一样的，不过这里就是可能性能高一些
 * @param bs64Data
 * @param contentType
 * @param sliceSize
 */
export function bs64toBlob(bs64Data: string, contentType: string, sliceSize = 512) {
  // WindowOrWorkerGlobalScope.atob() 对用base-64编码过的字符串进行解码，基本兼容所有浏览器
  const byteCharacters = window.atob(bs64Data)
  const byteArrays = []

  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize)

    const byteNumbers = new Array(slice.length)
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i)
    }

    const byteArray = new Uint8Array(byteNumbers)

    byteArrays.push(byteArray)
  }

  return new Blob(byteArrays, { type: contentType })
}

export function getRandomUserName() {
  const usernameList = [
    '初夏的忧伤',
    '看你背影',
    '爱吃西瓜子',
    '孤独是种安全感',
    '终究错过',
    '还你笑颜承你欢',
    '野花丛里',
    '不眠之夜',
    '心动过才放不下',
    '念不善言辞暖甜',
    '脂红粉白',
    '雾里寻你',
    '眼前人心上人',
    '亦心',
    '爱你爱到后退',
    '虚拟',
    '好梦不及重温',
    '開心就好',
    '前度桃花',
    '南山南',
    '澉约',
    '执着',
    '吟一曲流年殇',
    '撩妹局局长',
    '你还是没感动',
    '仿佛没有时间'
  ]
  return usernameList[random(0, usernameList.length - 1)]
}

export function getRandomAvatar() {
  const index = random(0, 66)
  return `https://packet-dev.oss-cn-hangzhou.aliyuncs.com/config/chat_members/avatar-${index}.jpg`
}

/**
 * 是否为今天
 * @param date
 */
export function isToday(date: string | number) {
  const d = new Date(date)
  const todayDate = new Date()
  return d.setHours(0, 0, 0, 0) == todayDate.setHours(0, 0, 0, 0)
}

/**
 * 是否为同一天
 */
export function isSameDay(d1: string | number, d2: string | number) {
  const date1 = new Date(d1)
  const date2 = new Date(d2)
  return date1.setHours(0, 0, 0, 0) === date2.setHours(0, 0, 0, 0)
}

/**
 * 是否为明天
 * @param d
 */
export function isTomorrow(d: string | number) {
  const date = new Date(d).setHours(0, 0, 0, 0)
  const today = new Date().setHours(0, 0, 0, 0)
  return date - today === 86400000
}

/**
 * 是否为昨天
 * @param d
 */
export function isYesterday(d: string | number) {
  const date = new Date(d).setHours(0, 0, 0, 0)
  const today = new Date().setHours(0, 0, 0, 0)
  return date - today === -86400000
}

/**
 * 是否为今天之前(昨天或者更远的之前)
 */
export function isBeforeToday(d: string | number) {
  const date = new Date(d).setHours(0, 0, 0, 0)
  const today = new Date().setHours(0, 0, 0, 0)
  return date < today
}

/**
 * 是否为今天之后(明天或者后天或者更之后)
 */
export function isAfterToday(d: string | number) {
  const date = new Date(d).setHours(0, 0, 0, 0)
  const today = new Date().setHours(0, 0, 0, 0)
  return date > today
}

export function randomDate(start: number, end = Date.now()) {
  return random(start, end)
}

export function addZero(n: number): string {
  return n < 10 ? `0${n}` : n.toString()
}

export function formatDate(separator = '-', t?: number) {
  const date = t ? new Date(t) : new Date()
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()

  return [addZero(year), addZero(month), addZero(day)].join(separator)
}

export function randomWords() {
  const words = [
    'A',
    'B',
    'C',
    'D',
    'E',
    'F',
    'G',
    'H',
    'I',
    'J',
    'K',
    'L',
    'M',
    'N',
    'O',
    'P',
    'Q',
    'R',
    'S',
    'T',
    'U',
    'V',
    'W',
    'X',
    'Y',
    'Z'
  ]
  return words[random(0, words.length - 1)]
}

export function getArrayRandom<T>(arr: T[]): T {
  return arr[random(0, arr.length - 1)]
}

/**
 * 获取今天 23:59:59 的时间戳
 */
export function getToDayEndTime() {
  const date = new Date()
  date.setHours(23, 59, 59)
  return date.getTime()
}

/**
 * 获取今天 00:00:00 的时间戳
 */
export function getToDayStartTime() {
  const date = new Date()
  date.setHours(0, 0, 0)
  return date.getTime()
}

/**
 * 填充0
 * replenish(BigInt(12)) => '0012'
 * @param num 整数
 * @param filler 填充物
 * @param total 最多几位
 */
export function replenish(num: BigInt, filler = '0', total = 4) {
  const dis = total - num.toString().length
  return dis <= 0 ? num.toString() : `${filler.repeat(dis)}${num}`
}

/**
 * 获取 url 中的 query
 * @param url ulr
 * @returns 返回一个对象
 */
export function getRouteQuery(url: string = window.location.href) {
  // 通过 ? 分割获取后面的参数字符串
  let urlStr = url.split('?')?.[1]
  if (!urlStr) {
    return {}
  }
  // 创建空对象存储参数
  let obj: { [p: string]: string } = {}
  // 再通过 & 将每一个参数单独分割出来
  let paramsArr = urlStr.split('&')
  for (let i = 0, len = paramsArr.length; i < len; i++) {
    // 再通过 = 将每一个参数分割为 key:value 的形式
    let arr = paramsArr[i].split('=')
    obj[arr[0]] = arr[1]
  }
  return obj
}

/**
 * 返回小数
 * @param v 数字
 * @returns 数字
 */
export function getDecimal(v: number): number {
  return Math.ceil(v) - Math.floor(v)
}

/**
 * 不依赖lodash
 * 随机值 min ~ max
 * @param min
 * @param max
 */
export function myRandom(min: number, max: number): number {
  return Math.round(Math.random() * (max - min)) + min
}
